#pragma once

#include "protocol.hpp"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

using namespace std;

enum
{
    USAGE_ERR = 0,
    SOCKET_ERR,
    CONNECT_ERR,
};

class calClient
{
public:
    calClient(string& serverip, uint16_t serverport)
    : _sockfd(-1),
      _serverip(serverip),
      _serverport(serverport)
    {}

    void initClient()
    {
        //创建socket
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd == -1)
            exit(SOCKET_ERR);
        cout << "create socket success, sockfd: " << _sockfd << endl;

        //绑定ip和port
        //由于不确定client的哪些端口被占用 所以无法手动绑定port 当client向server发送数据时由os自动为client分配port

        //client不需要进行监听
    }

    void startClient()
    {
        //与服务器建立连接
        struct sockaddr_in server;
        memset(&server, 0, sizeof server);
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(_serverip.c_str());
        server.sin_port = htons(_serverport);
        if (connect(_sockfd, (struct sockaddr*)&server, sizeof server) != 0)
        {
            cout << "connect failed" << endl;
            exit(CONNECT_ERR);
        }
        cout << "connect success" << endl;

        string inbuffer;//用于接收处理结果的缓冲区
        while (true)
        {
            //标准输入获取用户输入"x""op""y"
            string msg;
            cout << "#Enter ";
            getline(cin, msg);
            Request req;
            if (!parseMsg(msg, &req))//将输入的数据解析为结构化数据
            {
                cout << "输入格式有误 请重新输入" << endl;
                continue;
            }
            //请求序列化
            string req_content, req_str;
            req.serialize(&req_content);
            //为请求添加报头
            enLength(req_content, &req_str);
            //发送请求报文
            send(_sockfd, req_str.c_str(), req_str.size(), 0);

            //接收处理结果
            string res_str, res_content;
            if (!recvPackage(_sockfd, inbuffer, &res_str))
                return;
            //去掉处理结果的报头
            if (!deLength(res_str, &res_content))
                return;
            //处理结果反序列化
            Response res;
            if (!res.deserialize(res_content))
                return;
            //打印处理结果
            string response = "[server echo] ";
            switch (res._exitcode)
            {
            case 0:
                response += to_string(res._result);
                break;
            case 1:
                response += "div zero error";
                break;
            case 2:
                response += "mod zero error";
                break;
            case 3:
                response += "operator is invalid";
                break;
            default:
                response += "unknown error";
                break;
            }
            cout << response << endl;
        }
    }

    bool parseMsg(const string& msg, Request* out)
    {
        int pos = 0;
        while (pos < msg.size())
        {
            if (!isdigit(msg[pos]))
                break;
            pos++;
        }
        if (pos >= msg.size())//没找到运算符
            return false;
        string x = msg.substr(0, pos);
        string y = msg.substr(pos + 1, string::npos);
        if (x.empty() || y.empty())
            return false;
        out->_x = stoi(x);
        out->_y = stoi(y);
        out->_op = msg[pos];
        return true;
    }

private:
    int _sockfd;
    string _serverip;
    uint16_t _serverport;
};
